Skip to content

Conversation

JAORMX
Copy link
Collaborator

@JAORMX JAORMX commented Oct 2, 2025

Summary

Add support for exporting MCP server configurations as Kubernetes MCPServer resources with the --format flag.

Use Case

This feature enables a smooth development-to-production workflow for MCP servers:

  1. Local Development: Users can run and test MCP servers locally using thv run with various configurations (environment variables, volumes, OIDC, authorization policies, etc.)
  2. Export for Production: Once satisfied with the local configuration, users can export it as a Kubernetes manifest with thv export --format k8s
  3. Deploy to Cluster: Apply the exported manifest directly to their Kubernetes cluster for production deployment

This eliminates the need to manually recreate configurations when moving from local development to cluster deployment, reducing errors and accelerating the transition to production.

Changes

  • Add pkg/export package with k8s.go for converting RunConfig to MCPServer CRD
  • Enhance thv export command with --format flag (json/k8s)
  • Convert all RunConfig fields to appropriate MCPServer spec fields:
    • Image, transport, ports, and command arguments
    • Environment variables
    • Volume mounts
    • OIDC authentication configuration
    • Cedar authorization policies
    • Audit logging settings
    • OpenTelemetry and Prometheus telemetry
    • Tool filtering
  • Sanitize names to comply with Kubernetes naming requirements
  • Add comprehensive unit tests for all export functionality (32 tests)
  • Add e2e tests for export command with both formats
  • Fix linting issue in version.go

Test plan

  • All unit tests pass (32 new tests)
  • Linter passes
  • E2E tests created for both export formats

Usage

# Run and configure MCP server locally
thv run --name my-server \
  --env "API_KEY=secret" \
  --volume "/data:/data:ro" \
  --oidc-issuer "https://auth.example.com" \
  ghcr.io/my-org/my-mcp-server

# Test locally until satisfied...

# Export as Kubernetes MCPServer resource for production
thv export my-server ./my-server.yaml --format k8s

# Deploy to Kubernetes cluster
kubectl apply -f my-server.yaml

🤖 Generated with Claude Code

@JAORMX JAORMX force-pushed the add-k8s-export-format branch from 12741a7 to ea576eb Compare October 2, 2025 15:49
Copy link

codecov bot commented Oct 3, 2025

Codecov Report

❌ Patch coverage is 98.20359% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.50%. Comparing base (48db1ad) to head (78e058e).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/export/k8s.go 98.20% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2072      +/-   ##
==========================================
+ Coverage   49.25%   49.50%   +0.25%     
==========================================
  Files         244      245       +1     
  Lines       30920    31087     +167     
==========================================
+ Hits        15229    15391     +162     
- Misses      14556    14560       +4     
- Partials     1135     1136       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@danbarr danbarr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delayed reply. Found an issue that blocks applying these, the apiVersion is slightly wrong.

But a few other things I noticed:

  1. For servers with secrets, right now just nothing is put into the manifest. But it might be nice to ouput a warning to let users know they need to get one in place? Or maybe even stub out the secret definition in the manifest but output a message about creating the K8s secret before applying?

  2. I used it on a remote MCP server, expecting it to fail since remote servers aren't supported in K8s. But it did generate a manifest, just with an empty image. I think for now it should just error out instead of generating something that's unusable?

JAORMX and others added 2 commits October 13, 2025 14:05
Add support for exporting MCP server configurations as Kubernetes
MCPServer resources with the --format flag. Users can now export
their running servers to K8s manifests for deployment in Kubernetes.

Changes:
- Add pkg/export package with k8s.go for converting RunConfig to MCPServer CRD
- Enhance thv export command with --format flag (json/k8s)
- Convert all RunConfig fields to appropriate MCPServer spec fields
- Handle environment variables, volumes, OIDC, authz, audit, telemetry
- Sanitize names to comply with Kubernetes naming requirements
- Add comprehensive unit tests for all export functionality
- Add e2e tests for export command with both formats

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Signed-off-by: Juan Antonio Osorio <[email protected]>
Fix issues identified in PR review:

1. Fix APIVersion from toolhive.stacklok.com to toolhive.stacklok.dev
   - Update pkg/export/k8s.go to use correct API group
   - Update test assertions in pkg/export/k8s_test.go and test/e2e/export_test.go

2. Add validation for remote MCP servers
   - Remote servers are not supported in Kubernetes deployments
   - Return error if RemoteURL is set or Image is empty
   - Add unit tests for both error cases

3. Add warning for servers with secrets
   - Detect when secrets are present in RunConfig
   - Output warning to stderr explaining secrets must be created separately
   - Display list of secrets that need to be handled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@JAORMX JAORMX force-pushed the add-k8s-export-format branch from ea576eb to 78e058e Compare October 13, 2025 11:14
@JAORMX JAORMX requested a review from danbarr October 13, 2025 11:14
@danbarr
Copy link
Collaborator

danbarr commented Oct 13, 2025

@JAORMX updates are working well! Only other thing I was wondering, should the output be using the logger package? Just noting the differences in output format, like:

image

Compared to:
image

@JAORMX
Copy link
Collaborator Author

JAORMX commented Oct 14, 2025

@danbarr I don'think we need to use the logger package. We should, however, prettify that output 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants